home *** CD-ROM | disk | FTP | other *** search
/ Windows 95 API Bible / Windows 95 API Bible 3 Disc Set.iso / Win32 API Bible Book 3 of 3 / CHAPTE20 / IOPROC.C < prev    next >
C/C++ Source or Header  |  1996-04-29  |  19KB  |  601 lines

  1. #include <windows.h>
  2. #include <io.h>    
  3. #include <stdio.h>
  4. #include "IOProc.h"
  5.  
  6.  
  7. #if defined (WIN32)
  8.     #define IS_WIN32 TRUE
  9. #else
  10.     #define IS_WIN32 FALSE
  11. #endif
  12.  
  13. #define IS_NT      IS_WIN32 && (BOOL)(GetVersion() < 0x80000000)
  14. #define IS_WIN32S  IS_WIN32 && (BOOL)(!(IS_NT) && (LOBYTE(LOWORD(GetVersion()))<4))
  15. #define IS_WIN95   (BOOL)(!(IS_NT) && !(IS_WIN32S)) && IS_WIN32
  16.  
  17.  
  18.  
  19. HINSTANCE hInst;   // current instance
  20.  
  21. LPCTSTR lpszAppName = "MyApp";
  22. LPCTSTR lpszTitle   = "My Application"; 
  23.  
  24. // the rest of the stuff
  25. //......................
  26.  
  27. BOOL RegisterWin95( CONST WNDCLASS* lpwc );
  28.  
  29.  
  30. int APIENTRY WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance,
  31.                       LPTSTR lpCmdLine, int nCmdShow)
  32. {
  33.    MSG      msg;
  34.    HWND     hWnd; 
  35.    WNDCLASS wc;
  36.  
  37.    wc.style         = CS_HREDRAW | CS_VREDRAW | CS_OWNDC;
  38.    wc.lpfnWndProc   = (WNDPROC)WndProc;       
  39.    wc.cbClsExtra    = 0;                      
  40.    wc.cbWndExtra    = 0;                      
  41.    wc.hInstance     = hInstance;              
  42.    wc.hIcon         = LoadIcon (hInstance, lpszAppName); 
  43.    wc.hCursor       = LoadCursor(NULL, IDC_ARROW);
  44.    wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
  45.    wc.lpszMenuName  = lpszAppName;              
  46.    wc.lpszClassName = lpszAppName;              
  47.  
  48.    if ( IS_WIN95 )
  49.    {
  50.       if ( !RegisterWin95( &wc ) )
  51.          return( FALSE );
  52.    }
  53.    else if ( !RegisterClass( &wc ) )
  54.       return( FALSE );
  55.  
  56.    hInst = hInstance; 
  57.  
  58.    hWnd = CreateWindow( lpszAppName, 
  59.                         lpszTitle,    
  60.                         WS_OVERLAPPEDWINDOW, 
  61.                         CW_USEDEFAULT, 0, 
  62.                         CW_USEDEFAULT, 0,  
  63.                         NULL,              
  64.                         NULL,              
  65.                         hInstance,         
  66.                         NULL               
  67.                       );
  68.  
  69.    if ( !hWnd ) 
  70.       return( FALSE );
  71.  
  72.    ShowWindow( hWnd, nCmdShow ); 
  73.    UpdateWindow( hWnd );         
  74.  
  75.    while( GetMessage( &msg, NULL, 0, 0) )   
  76.    {
  77.       TranslateMessage( &msg ); 
  78.       DispatchMessage( &msg );  
  79.    }
  80.  
  81.    return( msg.wParam ); 
  82. }
  83.  
  84.  
  85. BOOL RegisterWin95( CONST WNDCLASS* lpwc )
  86. {
  87.     WNDCLASSEX wcex;
  88.  
  89.    wcex.style         = lpwc->style;
  90.    wcex.lpfnWndProc   = lpwc->lpfnWndProc;
  91.    wcex.cbClsExtra    = lpwc->cbClsExtra;
  92.    wcex.cbWndExtra    = lpwc->cbWndExtra;
  93.    wcex.hInstance     = lpwc->hInstance;
  94.    wcex.hIcon         = lpwc->hIcon;
  95.    wcex.hCursor       = lpwc->hCursor;
  96.    wcex.hbrBackground = lpwc->hbrBackground;
  97.    wcex.lpszMenuName  = lpwc->lpszMenuName;
  98.    wcex.lpszClassName = lpwc->lpszClassName;
  99.  
  100.    // Added elements for Windows 95.
  101.    //...............................
  102.    wcex.cbSize = sizeof(WNDCLASSEX);
  103.    wcex.hIconSm = LoadImage(wcex.hInstance, lpwc->lpszClassName, 
  104.                             IMAGE_ICON, 16, 16,
  105.                             LR_DEFAULTCOLOR );
  106.             
  107.    return RegisterClassEx( &wcex );
  108. }
  109.  
  110.  
  111.  
  112. #define USR_INBLOCK              (WM_USER+101)
  113. #define USR_MMIOM_PROC_VERSION   (WM_USER+10001)
  114. #define MSG_LEN                  1024
  115. #define DATABLOCK_SIZE           300*1024 // 300K
  116.  
  117. char         msg[MSG_LEN+1];
  118. HWND         hListBox = NULL;
  119. HWAVEIN      hwi;
  120. WAVEHDR      wavehdr;
  121. WAVEFORMATEX wfx;
  122. MMRESULT     rc;
  123. LPMMIOPROC   pIOProc = NULL;
  124.  
  125. VOID RecordWave(HWND hWnd);
  126. VOID CreateRiff();
  127.  
  128. LONG CALLBACK WaveIOProc(LPMMIOINFO lpmmioInfo, UINT uMsg, 
  129.                          LPARAM lParam1, LPARAM lParam2);
  130.  
  131.  
  132. LRESULT CALLBACK WndProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam )
  133. {
  134.    switch( uMsg )
  135.    {
  136.       case WM_CREATE:
  137.               // Create ListBox
  138.               //...............
  139.  
  140.               hListBox = CreateWindow( "LISTBOX", "",    
  141.                                        WS_CHILD | LBS_NOTIFY | 
  142.                                        WS_VSCROLL | WS_BORDER | 
  143.                                        WS_VISIBLE | LBS_NOINTEGRALHEIGHT, 
  144.                                        0, 0, 
  145.                                        0, 0,  
  146.                                        hWnd,              
  147.                                        (HMENU)101,              
  148.                                        hInst,         
  149.                                        NULL );
  150.  
  151.               // install custom I/O procedure WaveIOProc()
  152.               //..........................................
  153.               
  154.               pIOProc = mmioInstallIOProc( (FOURCC)mmioStringToFOURCC("WAV", 0),
  155.                                            (LPMMIOPROC)WaveIOProc, MMIO_INSTALLPROC);
  156.  
  157.               if (!pIOProc)
  158.                   MessageBox(hWnd, "Install I/O proc failure.", NULL, MB_OK);
  159.  
  160.               // allocate data block
  161.               // using only one data block in order to
  162.               // keep this example simple
  163.               //......................................
  164.  
  165.               wavehdr.lpData = HeapAlloc(GetProcessHeap(),             
  166.                                          HEAP_ZERO_MEMORY,             
  167.                                          DATABLOCK_SIZE);
  168.               wavehdr.dwBufferLength = DATABLOCK_SIZE;
  169.               break;
  170.  
  171.       case WM_SIZE :
  172.               MoveWindow( hListBox, 0, 0, 
  173.                           LOWORD( lParam ), 
  174.                           HIWORD( lParam ), TRUE );
  175.               break;
  176.  
  177.       case WM_COMMAND :
  178.               switch( LOWORD( wParam ) )
  179.               {
  180.                  case IDM_TEST:
  181.                         SendMessage(hListBox, LB_RESETCONTENT, 0, 0);
  182.                         SendMessage(hListBox, LB_ADDSTRING, 0, 
  183.                                     (LPARAM)"Recording, please wait...");
  184.  
  185.                         // record some wave audio
  186.                         //.......................
  187.  
  188.                         RecordWave(hWnd);
  189.                         break;
  190.  
  191.                  case IDM_ABOUT :
  192.                         DialogBox( hInst, "AboutBox", hWnd, About );
  193.                         break;
  194.  
  195.                  case IDM_EXIT :
  196.                         if (hwi)
  197.                         {
  198.                             MessageBox(NULL, "Still recording, please wait...",
  199.                                        NULL, MB_OK);
  200.                             break;
  201.                         }
  202.                         DestroyWindow(hWnd);
  203.                         break;
  204.               }
  205.               break;
  206.  
  207.       case USR_INBLOCK :
  208.               {
  209.                  // stop recording                                               
  210.                   //...............                                               
  211.                                                                     
  212.                   waveInStop(hwi);
  213.                  waveInReset(hwi);
  214.  
  215.                   // Unprepare header
  216.                   //.................
  217.                                                                     
  218.                   waveInUnprepareHeader(hwi, &wavehdr, sizeof(WAVEHDR));
  219.                                                                     
  220.                   waveInClose(hwi);
  221.                  hwi = NULL;
  222.  
  223.                  // create the RIFF file new.wav
  224.                  //.............................
  225.  
  226.                  CreateRiff();
  227.               }
  228.               break;
  229.  
  230.       case WM_DESTROY:
  231.               // free data block
  232.               //................
  233.  
  234.               if (wavehdr.lpData)
  235.               {
  236.                   HeapFree(GetProcessHeap(), 0, wavehdr.lpData);
  237.                   wavehdr.lpData = NULL;
  238.               }
  239.  
  240.               // un-install custom I/O procedure WaveIOProc()
  241.               //.............................................
  242.  
  243.               mmioInstallIOProc( (FOURCC)mmioStringToFOURCC("WAV ", 0),
  244.                                  (LPMMIOPROC)WaveIOProc, MMIO_REMOVEPROC);
  245.  
  246.               PostQuitMessage(0);
  247.               break;
  248.  
  249.       default :
  250.             return( DefWindowProc( hWnd, uMsg, wParam, lParam ) );
  251.    }
  252.  
  253.    return( 0L );               
  254. }
  255.  
  256.  
  257. VOID CALLBACK waveInProc( HWAVEIN hwi, UINT uMsg, DWORD dwInstance, DWORD dwParam1, DWORD dwParam2 )
  258. {
  259.    // post message to process this input block received
  260.    // NOTE: callback cannot call other waveform functions
  261.    //....................................................
  262.  
  263.    if (uMsg == WIM_DATA)
  264.       PostMessage((HWND)dwInstance, USR_INBLOCK, 0, dwParam1);
  265. }
  266.  
  267.  
  268. VOID RecordWave(HWND hWnd)
  269. {
  270.    WAVEINCAPS wic;                                               
  271.     
  272.     hwi = NULL;
  273.                                                                     
  274.    rc = waveInGetDevCaps(0, &wic, sizeof(wic));               
  275.        
  276.    if (rc == MMSYSERR_NOERROR)                                  
  277.    {
  278.        wfx.nChannels      = wic.wChannels;  // use DevCaps # channels
  279.        wfx.nSamplesPerSec = 11025;          // 11.025 kHz (11.025 * 1000)
  280.  
  281.        wfx.wFormatTag      = WAVE_FORMAT_PCM;                          
  282.          wfx.wBitsPerSample  = 8;                                        
  283.         wfx.nBlockAlign     = wfx.nChannels * wfx.wBitsPerSample / 8;   
  284.         wfx.nAvgBytesPerSec = wfx.nSamplesPerSec * wfx.nBlockAlign;     
  285.         wfx.cbSize          = 0;
  286.        
  287.        // open waveform input device
  288.        //...........................
  289.  
  290.        rc = waveInOpen(&hwi, 0, &wfx, (DWORD)(VOID*)waveInProc, (DWORD)hWnd,                   
  291.                        CALLBACK_FUNCTION);                                          
  292.        
  293.        if (rc != MMSYSERR_NOERROR)                              
  294.        {                                                        
  295.            waveInGetErrorText(rc, msg, MSG_LEN),                    
  296.            MessageBox(hWnd, msg, NULL, MB_OK);
  297.            return;
  298.        }
  299.        
  300.    }
  301.    
  302.     // prepare buffer block
  303.     //.....................
  304.  
  305.    rc = waveInPrepareHeader(hwi, &wavehdr, sizeof(WAVEHDR));
  306.                                                                     
  307.     // add buffer to the input queue                            
  308.                                                                     
  309.     if (rc == MMSYSERR_NOERROR)
  310.         rc = waveInAddBuffer(hwi, &wavehdr, sizeof(WAVEHDR));
  311.                                                                     
  312.     if (rc != MMSYSERR_NOERROR)                                  
  313.     {                                                            
  314.         waveInGetErrorText(rc, msg, MSG_LEN);
  315.         waveInClose(hwi);                        
  316.         MessageBox(hWnd, msg, NULL, MB_OK);
  317.         return;                                              
  318.     }                                                               
  319.                                                                     
  320.     // start recording                                              
  321.     //................                                              
  322.                                                                     
  323.     rc = waveInStart(hwi);
  324. }
  325.  
  326.  
  327.  
  328. VOID CreateRiff() 
  329.     HMMIO       hmmio;          // file handle for open file 
  330.     MMCKINFO    ciRiffChunk;    // main RIFF chunk information 
  331.     MMCKINFO    ciSubChunk;     // subchunk information
  332.     LONG        nVersion;       // custom I/O proc version
  333.     MMIOINFO    mmioInfo;
  334.  
  335.     // rename a prev. 'new.wav' file (if one exists)
  336.     // to 'new.bak'
  337.     //..............................................
  338.  
  339.     mmioRename("new.wav", "new.bak", NULL, 0);
  340.  
  341.     // open the wave file using an internal I/O buffer
  342.     //................................................ 
  343.  
  344.     mmioInfo.dwFlags     = 0;
  345.     mmioInfo.fccIOProc   = mmioStringToFOURCC("WAV ", 0);
  346.     mmioInfo.pIOProc     = (LPMMIOPROC)WaveIOProc;
  347.     mmioInfo.wErrorRet   = 0;
  348.     mmioInfo.htask       = 0;
  349.     mmioInfo.cchBuffer   = 0;
  350.     mmioInfo.pchBuffer   = 0;
  351.     mmioInfo.pchNext     = 0;
  352.     mmioInfo.pchEndRead  = 0;
  353.     mmioInfo.pchEndWrite = 0;
  354.     mmioInfo.lBufOffset  = 0;
  355.     mmioInfo.lDiskOffset = 0;
  356.     mmioInfo.adwInfo[0]  = 0;
  357.     mmioInfo.adwInfo[1]  = 0;
  358.     mmioInfo.adwInfo[2]  = 0;
  359.     mmioInfo.adwInfo[3]  = 0;
  360.     mmioInfo.dwReserved1 = 0;
  361.     mmioInfo.dwReserved2 = 0;
  362.     mmioInfo.hmmio       = 0;
  363.  
  364.     hmmio = mmioOpen("new.wav", &mmioInfo, 
  365.                      MMIO_CREATE | MMIO_WRITE | MMIO_ALLOCBUF);
  366.  
  367.     if(!hmmio) 
  368.     { 
  369.         MessageBox(NULL, "Failed to open file.", NULL, MB_OK); 
  370.         return; 
  371.     }
  372.  
  373.     // attempt to increase the size of the buffer to 128K
  374.     //...................................................
  375.  
  376.     mmioSetBuffer(hmmio, NULL, 131072, 0);                                                        
  377.  
  378.     // get customer I/O proc version number and display it
  379.     //....................................................
  380.  
  381.     nVersion = mmioSendMessage(hmmio, USR_MMIOM_PROC_VERSION, 0, 0);
  382.  
  383.     sprintf(msg, "Custom I/O procedure version: %ld.%ld installed", 
  384.             HIWORD(nVersion), LOWORD(nVersion));
  385.                  
  386.     SendMessage(hListBox, LB_ADDSTRING, 0, (LPARAM)msg);
  387.  
  388.     // create main 'RIFF' chunk
  389.     //.........................
  390.  
  391.     mmioSeek(hmmio, 0, SEEK_SET); // reset to beginning of file.
  392.  
  393.     ciRiffChunk.fccType   = mmioFOURCC('W', 'A', 'V', 'E');
  394.     ciRiffChunk.cksize    = 0L;  // mmio will determine corect size
  395.     rc = mmioCreateChunk(hmmio, &ciRiffChunk, MMIO_CREATERIFF);
  396.  
  397.     // create 'fmt' chunk
  398.     //...................
  399.  
  400.     ciSubChunk.ckid   = mmioStringToFOURCC("fmt ", 0);
  401.     ciSubChunk.cksize = sizeof(WAVEFORMATEX);
  402.  
  403.     rc = mmioCreateChunk(hmmio, &ciSubChunk, 0);
  404.     rc = mmioWrite(hmmio, (HPSTR)&wfx, sizeof(WAVEFORMATEX));
  405.  
  406.  
  407.     // ascend out of 'fmt' chunk back to the main 'RIFF' chunk
  408.     //........................................................
  409.  
  410.     rc = mmioAscend(hmmio, &ciSubChunk, 0);
  411.     
  412.     // create 'data' chunk
  413.     // if the cksize is incorrect, when we ascend out of the chunk,
  414.     // the cksize will be updated to it's actual size
  415.     //.............................................................
  416.  
  417.     ciSubChunk.ckid   = mmioStringToFOURCC("data", 0);
  418.     ciSubChunk.cksize = DATABLOCK_SIZE;
  419.  
  420.     rc = mmioCreateChunk(hmmio, &ciSubChunk, 0);
  421.  
  422.     // okay, now lets write the data to the buffer the hard 
  423.     // way (manually) without the mmioWrite() function. 
  424.     // The following loop only moves one byte at a time to
  425.     // simplify the example.
  426.     // If we were going to write the data using the write 
  427.     // statement, it would look like the following:
  428.     //           mmioWrite(hmmio, (HPSTR)wavehdr.lpData, 
  429.     //                     (LONG)wavehdr.dwBytesRecorded);
  430.     //.....................................................
  431.  
  432.     {
  433.        LONG i;
  434.  
  435.        mmioGetInfo(hmmio, &mmioInfo, 0);
  436.  
  437.        for (i = 0; i < (LONG)wavehdr.dwBytesRecorded; i++)
  438.        {
  439.           if (mmioInfo.pchNext == mmioInfo.pchEndWrite)
  440.           {
  441.               mmioInfo.dwFlags |= MMIO_DIRTY;  // we have modified the buffer
  442.               mmioAdvance(hmmio, &mmioInfo, MMIO_WRITE);
  443.           }
  444.  
  445.           *(mmioInfo.pchNext)++ = (BYTE) *(wavehdr.lpData+i);
  446.        }
  447.  
  448.        mmioInfo.dwFlags |= MMIO_DIRTY;  // we have modified the buffer
  449.        
  450.        mmioSetInfo(hmmio, &mmioInfo, 0);
  451.     }
  452.  
  453.     // ascend out of 'data' chunk back to the main 'RIFF' chunk
  454.     // this corrects the chunk length if not correctly
  455.     // specified when the chunk was created.
  456.     //.........................................................
  457.  
  458.     rc = mmioAscend(hmmio, &ciSubChunk, 0);
  459.     
  460.     // ascend out of the main 'RIFF' chunk
  461.     //....................................
  462.  
  463.     rc = mmioAscend(hmmio, &ciRiffChunk, 0);
  464.  
  465.     // flush buffer and close file
  466.     //............................
  467.  
  468.     rc = mmioFlush(hmmio, 0);
  469.     rc = mmioClose(hmmio, 0);
  470.     
  471.     SendMessage(hListBox, LB_ADDSTRING, 0, 
  472.                 (LPARAM)"RIFF WAVE file 'new.wav' created."); 
  473. }
  474.  
  475. LONG CALLBACK WaveIOProc(LPMMIOINFO lpmmioInfo, UINT uMsg, 
  476.                          LPARAM lParam1, LPARAM lParam2)
  477. {
  478.     static int  file = 0;
  479.            int  nFlag;
  480.            int  nStatus;
  481.            LONG lStatus;
  482.  
  483.  
  484.     switch(uMsg)
  485.     {
  486.        // Open
  487.        //.....
  488.  
  489.        case MMIOM_OPEN:
  490.               if (lpmmioInfo->dwFlags & MMIO_READ)
  491.                   nFlag = OF_READ;
  492.               else if (lpmmioInfo->dwFlags & MMIO_WRITE)
  493.                   nFlag = OF_WRITE;
  494.               else if (lpmmioInfo->dwFlags & MMIO_CREATE)
  495.               {
  496.                   file = _lcreat((LPSTR)lParam1, 0);
  497.  
  498.                   if (file == -1)
  499.                       return(MMIOERR_CANNOTOPEN);
  500.                   else
  501.                   {
  502.                       lpmmioInfo->lDiskOffset = 0;
  503.                       return(0);
  504.                   }
  505.               }
  506.               else  // default
  507.               {
  508.                   nFlag = OF_READWRITE;
  509.               }
  510.  
  511.               file = _lopen((LPSTR)lParam1, nFlag);
  512.  
  513.               if (file == -1)
  514.               {
  515.                   if (lpmmioInfo->dwFlags & MMIO_WRITE)
  516.                   {
  517.                       file = _lcreat((LPSTR)lParam1, 0);
  518.                   }
  519.               }
  520.  
  521.               if (file == -1)
  522.                   return(MMIOERR_CANNOTOPEN);
  523.               else
  524.               {
  525.                   lpmmioInfo->lDiskOffset = 0;
  526.                   return(0);
  527.               }
  528.  
  529.               break;
  530.  
  531.        // Close
  532.        //......
  533.  
  534.        case MMIOM_CLOSE:
  535.               return( _lclose(file) );
  536.  
  537.        // Read
  538.        //.....
  539.  
  540.        case MMIOM_READ:
  541.               nStatus = _lread(file, (LPSTR)lParam1, (int)lParam2);
  542.               lpmmioInfo->lDiskOffset += (int)lParam2;
  543.               return( (LONG)nStatus );
  544.  
  545.        // Write
  546.        //......
  547.  
  548.        case MMIOM_WRITE:
  549.        case MMIOM_WRITEFLUSH:
  550.               nStatus = _lwrite(file, (LPSTR)lParam1, (int)lParam2);
  551.               lpmmioInfo->lDiskOffset += (int)lParam2;
  552.               return( (LONG)nStatus );
  553.              
  554.  
  555.        // Seek
  556.        //.....
  557.  
  558.        case MMIOM_SEEK:
  559.               lStatus = _llseek(file, (LONG)lParam1, (int)lParam2);
  560.               lpmmioInfo->lDiskOffset = lStatus;
  561.               return(lStatus);
  562.  
  563.        // Version (custom message)
  564.        //.........................
  565.  
  566.        case USR_MMIOM_PROC_VERSION:
  567.               return( MAKELONG(0, 1));  // version 1.00
  568.     }
  569.  
  570.     return(0);
  571. }
  572.  
  573.  
  574.  
  575. LRESULT CALLBACK About( HWND hDlg,           
  576.                         UINT message,        
  577.                         WPARAM wParam,       
  578.                         LPARAM lParam)
  579. {
  580.    switch (message) 
  581.    {
  582.        case WM_INITDIALOG: 
  583.                return (TRUE);
  584.  
  585.        case WM_COMMAND:                              
  586.                if (   LOWORD(wParam) == IDOK         
  587.                    || LOWORD(wParam) == IDCANCEL)    
  588.                {
  589.                        EndDialog(hDlg, TRUE);        
  590.                        return (TRUE);
  591.                }
  592.                break;
  593.    }
  594.  
  595.    return (FALSE); 
  596. }
  597.  
  598.  
  599.  
  600.